/*
 * ethernet.c
 *
 * Created: 12/22/2011 11:50:18 AM
 *  Author: Administrator
 */ 
#include <avr/delay.h>
#include "ethernet.h"

uint8_t get_socket0_status(void)
{
	// Here you should referee to the data sheet to see which register should be read.
	// referee back to page 16
	return ((uint8_t) wiznet_read(S0_SR));
}

// This method interacts with socket zero only, check socket zero registers in the data sheet to know how to use them
// to accomplish the required tasks.
uint8_t socket(uint8_t eth_protocol,uint16_t tcp_port)
{
	if(wiznet_read(S0_SR) == SOCK_CLOSE_WAIT) // this method should close socket zero if it is already closed on client side.
		close();

	wiznet_write(S0_MR,eth_protocol); // then it should set socket zero mode according to the passed in eth_protocol variable
	
	printf("Parameter TCP Port %d\n",0x0050);
	
	wiznet_write(S0_PORT,0x00);// then it should define the port number associated with this socket
	wiznet_write(S0_PORT+1,0x50);
	//wiznet_write(S0_PORT+1,(tcp_port>>8 & 0xFF));
	printf("higher byte of port \%d\n",wiznet_read(S0_PORT));
	//wiznet_write(S0_PORT,(tcp_port & 0xFF));
	printf("lower byte of port \%d\n",wiznet_read(S0_PORT+1));
	wiznet_write(S0_CR,CR_OPEN);// then it should open the socket and wait till it is opened
	while(wiznet_read(S0_CR)!=0x00){};
	
	printf("Socket opened with status %x\n",wiznet_read(S0_SR));
	if(wiznet_read(S0_SR)== SOCK_INIT)	// then it should make sure the socket is initialized correctly and return true in that case
		return 0x01;
		
	else
		return 0x00;// in case of failure return false and close the socket just in case!	
			
}

// This method interacts with socket zero only, check socket zero registers in the data sheet to know how to use them
// to accomplish the required tasks.
void close(void)
{
   // send close command
   wiznet_write(S0_CR,CR_CLOSE);
   // wait till it is already closed.
   while (wiznet_read(S0_CR)!=0x00) {};

}

void disconnect(void)
{
   // send disconnect command
   wiznet_write(S0_CR,CR_DISCON);
   // wait till it is already disconnected.
   while (wiznet_read(S0_CR)!=0x00) {};
}

uint8_t listen(void)
{
	if(wiznet_read(S0_SR)!=SOCK_INIT)	// make sure socket is already initialized correctly.      <---------------->
			return 0x00;				// other wise return zero (false)
			
	wiznet_write(S0_CR,CR_LISTEN);		// send listen command to socket zero
	
	while (wiznet_read(S0_CR)!=0x00) {};	// wait till it is executed
	
	if(wiznet_read(S0_SR)==SOCK_LISTEN) // if the socket status is changed to listening return one (true)
		return 0x01;
	else				// otherwise return zero (false)
		return 0x00;
}

uint16_t send(const uint8_t *buf,uint16_t buflen)
{
	uint16_t tmp = buflen;
	// given the required data and its length
	int count =0;
	while(wiznet_read(SO_TX_FSR)<buflen)	// first make sure the transmission buffer on the ship has free space enough to hold your buffer
	{
		_delay_ms(1);		// otherwise wait 1 ms and try to check the buffer length once again	
		count++;
	}
		
	if(count >= 1000) // maximum for 1 second then return zero (false) to indicate an error (do not forget to disconnect the socket)
	{
		return 0x0000;
	}
	
	  uint16_t offset = wiznet_read(S0_TX_WR) & TX_BUF_MASK;    // if there are enough size in the transmission buffer on wiznet ship start sending the data.
	uint16_t startAdd =  TXBUFADDR + offset;
	int i=0;
	while(tmp>0)
	{
		wiznet_write(startAdd,buf[i]);
		i++;
		tmp--;
		startAdd++;
		
	}	
			
	wiznet_write(S0_TX_WR,S0_TX_WR+buflen);
	
	wiznet_write(S0_CR,CR_SEND);
	while (wiznet_read(S0_CR)!=0x00) {};
	return 0x0001;
	
	/*if((offset + buflen ) > (TX_BUF_MASK + 1))
	{
		uint16_t upper_size = (TX_BUF_MASK+1) - offset;
		memcpy((void *)buf,(void *)startAdd,upper_size);
		buf += upper_size;
		uint16_t left_size = buflen - upper_size; 
		memcpy((void *)buf,(void *)TXBUFADDR,left_size);
	}	
	else
	{
		memcpy((void *)buf,&startAdd,buflen);
	}*/
	// to do that you have to read the start address of the free space on the wiznet ship first.
	
	
	// make a loop to calculate the real address relative to the start address you just got from the wiznet ship
	// referee to the data sheet page 33 example and study it well.
	
	// finally write back the new start address for the free space on the ship.
	// and send command SEND to the ship so it starts sending the buffer on the wires
	// and wait till it is already sent.
}

uint16_t recv(uint8_t *buf,uint16_t buflen)
{
	// make sure the request buffer size is not bigger than the maximum buffer size.
	// otherwise truncate it
	uint16_t tmp = buflen;
	//if(wiznet_read(S0_RX_RSR)>buflen)
		//return 0x0000;
	
	uint16_t offset = wiznet_read(S0_RX_RD); // read the start address of the read buffer on the chip
	offset = offset<<8;
	offset |= wiznet_read(S0_RX_RD+1) & 0x00FF;
	printf("Offset: %x\n",offset);
	uint16_t startAddr = RXBUFADDR+offset & RX_BUF_MASK;
    int i=0;
	while(tmp>0)		// make a loop to read all the bytes and store them in buf[i]
	{
		buf[i] = wiznet_read(startAddr);
		printf("Buffer[i]: %c", buf[i]);
		startAddr++;
		i++;
		tmp--;
	}
	wiznet_write(S0_RX_RD,(S0_RX_RD+buflen));		// write back the reading address to make the chip points to the next unread part of the buffer
	buf[++i]= '\0';	// add '\0' to make the end of the buffer.
	wiznet_write(S0_CR,CR_RECV);	// finally send receive command to the chip and wait for it to process the command
	while (wiznet_read(S0_CR)!=0x00) {};
    return 0x0001;
    
	// you can simply wait 5 us to make sure the command is executed.
	
}

uint16_t recv_size(void)
{
	uint16_t offset = wiznet_read(S0_RX_RSR); // read the start address of the read buffer on the chip
	offset = offset<<8;
	offset |= wiznet_read(S0_RX_RSR+1) & 0x00FF;
	return	offset;// this method should read the socket zero buffer size in wiznet chip.
}
